﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LINQToolKit.Douban.Entities;
using LINQToolKit.Mapping;
using LINQToolKit.Douban.Processors;

using LINQToolKit;
using LINQToolKit.Configuration;

namespace  LINQToolKit.Douban
{
    public sealed class DoubanContext : DataContext
    {
        public DoubanContext()
            : this(ContextConfiguration.Default, XmlMappingSource.Default)
        {

        }

        public DoubanContext(IMappingSource mappingSource)
            : this(ContextConfiguration.Default, mappingSource)
        {
        }

        public DoubanContext(ContextConfiguration config, IMappingSource mappingSource)
            : base(config, mappingSource)
        {
        }

        /// <summary>
        /// Returns the people entity of current user
        /// </summary>
        public People Me
        {
            get 
            {
                if (this.Configuration.Parameters.ContainsKey("me"))
                {
                    Uri meUrl = new Uri(this.Configuration.Parameters["me"]);
                    return (People)this.CreateProvider().SelectOne(typeof(People), meUrl);   
                }

                return null;
            }
        }

        private void DoSomeRequest(Uri requestUrl, string httpMethod, string content)
        {
            var request = this.CreateRequest();
            var result = request.Execute(requestUrl, httpMethod, content);

            if (!result.Success)
            {
                throw new RequestException(result);
            }
        }
        public void CommentMiniBlog(string miniBlogId, string content)
        {
            miniBlogId.AssertNull("miniBlogId");
            content.AssertNull("content");
            var uri = this.Configuration.Parameters["postCommentOnMiniBlogUri"];
            var template = this.Configuration.Parameters["postCommentOnMiniBlogContent"];

            this.DoSomeRequest(new Uri(string.Format(uri, miniBlogId)), "POST", string.Format(template, content));
        }

        public void ParticipateEvent(string eventId)
        {
            eventId.AssertNull("eventId");
            var uri = this.Configuration.Parameters["partipateEventUri"];

            this.DoSomeRequest(new Uri(string.Format(uri, eventId)), "POST", null);
        }

        public void FollowEvent(string eventId)
        {
            eventId.AssertNull("eventId");
            var uri = this.Configuration.Parameters["followEventUri"];

            this.DoSomeRequest(new Uri(string.Format(uri, eventId)), "POST", null);
        }

        public void QuitEvent(string eventId)
        {
            eventId.AssertNull("eventId");
            var uri = this.Configuration.Parameters["quiteEventUri"];

            this.DoSomeRequest(new Uri(string.Format(uri, eventId)), "DELETE", null);
        }

        public void DeleteEvent(string eventId, string reason)
        {
            eventId.AssertNull("eventId");
            reason.AssertNull("reason");
            var uri = this.Configuration.Parameters["deleteEventUri"];
            string content = this.Configuration.Parameters["deleteEventContent"];

            this.DoSomeRequest(new Uri(string.Format(uri, eventId)), "DELETE", string.Format(content, reason));
        }

        public void CommentOnReco(string recommendId, string content)
        {
            recommendId.AssertNull("recommendId");
            content.AssertNull("content");
            var uri = this.Configuration.Parameters["postCommentOnRecoUri"];
            string template = this.Configuration.Parameters["postCommentOnRecoContent"];

            this.DoSomeRequest(new Uri(string.Format(uri, recommendId)), "POST", string.Format(template, content));
        }

        public void DeleteCommentOnReco(string recommendId, string commentId)
        {
            recommendId.AssertNull("recommendId");
            commentId.AssertNull("commentId");
            var uri = this.Configuration.Parameters["deleteCommentOnRecoUri"];

            this.DoSomeRequest(
                new Uri(string.Format(uri, recommendId, commentId)),
                "POST",
                null);
        }

        public void SetMailsRead(string[] mails)
        {
            mails.AssertNull("mails");
            var sbContent = new StringBuilder();
            var setMailReadUri = this.Configuration.Parameters["setMailReadUri"];
            var setMailReadHeader = this.Configuration.Parameters["setMailReadHeader"];
            var setMailReadEntry = this.Configuration.Parameters["setMailReadEntry"];

            foreach (var item in mails)
            {
                sbContent.AppendFormat(setMailReadEntry, item);
            }

            this.DoSomeRequest(
                new Uri(setMailReadUri), "PUT", string.Format(setMailReadHeader, sbContent.ToString()));
        }

        public void DeleteMails(string[] mails)
        {
            mails.AssertNull("mails");
            var sbContent = new StringBuilder();
            var setMailReadUri = this.Configuration.Parameters["setMailReadUri"];
            var deleteMailPostHeader = this.Configuration.Parameters["deleteMailPostHeader"];
            var deleteMailPostEntry = this.Configuration.Parameters["deleteMailPostEntry"];

            foreach (var item in mails)
            {
                sbContent.AppendFormat(deleteMailPostEntry, item);
            }

            this.DoSomeRequest(
                new Uri(setMailReadUri), "POST", string.Format(deleteMailPostHeader, sbContent.ToString()));
        }

        public bool IsTokenAvailabe(string token)
        {
            token.AssertNull("token");
            var uri = this.Configuration.Parameters["validateToken"];
            var request = this.CreateRequest().Execute(
                new Uri(string.Format(uri, token)), "GET", null);

            return request.Success;
        }

        public void CancelToken(string token)
        {
            token.AssertNull("token");
            var uri = this.Configuration.Parameters["cancelToken"];

            this.DoSomeRequest(
                new Uri(string.Format(uri, token)), "DELETE", null);
        }

        public IEntityTable<People> Peoples
        {
            get { return this.GetTable<People>(); }
        }

        public IEntityTable<Book> Books
        {
            get { return this.GetTable<Book>(); }
        }

        public IEntityTable<Music> Musics
        {
            get { return this.GetTable<Music>(); }
        }

        public IEntityTable<Movie> Movies
        {
            get { return this.GetTable<Movie>(); }
        }

        public IEntityTable<Review> Reviews
        {
            get { return this.GetTable<Review>(); }
        }

        public IEntityTable<Collection> Collections
        {
            get { return this.GetTable<Collection>(); }
        }

        public IEntityTable<MiniBlog> MiniBlogs
        {
            get { return this.GetTable<MiniBlog>(); }
        }

        public IEntityTable<Note> Notes
        {
            get { return this.GetTable<Note>(); }
        }

        public IEntityTable<Event> Events
        {
            get { return this.GetTable<Event>(); }
        }

        public IEntityTable<Recommendation> Recommends
        {
            get { return this.GetTable<Recommendation>(); }
        }

        public IEntityTable<Mail> Mails
        {
            get { return this.GetTable<Mail>(); }
        }
    }
}
